#include "string_utilities.h"

using std::cerr;
using std::endl;
using std::ios;
using std::string;
using std::vector;
using std::stringstream;

const std::string delim = " \t\r\n";

string trim_right(const string & s, const string & t)
{
	string d(s);
	string::size_type i(d.find_last_not_of(t));
	if (i == string::npos) return "";
	else return d.erase(d.find_last_not_of(t) + 1);
}

string trim_left(const string & s, const string & t)
{
	string d(s);
	return d.erase(0, s.find_first_not_of(t));
}

string trim(const string & s, const string & t)
{
	string d(s);
	return trim_left(trim_right(d, t), t);
}

unsigned long split(const std::string& s, std::vector<std::string>& tokens,
		const std::string& delim, bool remove_empty)
{
	std::ostringstream word;
	for (size_t n = 0; n < s.size(); ++n)
	{
		if (std::string::npos == delim.find(s[n])) word << s[n];
		else
		{
			if (!word.str().empty() || !remove_empty)
				tokens.push_back(word.str());
			word.str("");
		}
	}
	if (!word.str().empty() || !remove_empty) tokens.push_back(word.str());
	return tokens.size();
}

bool isDouble(const std::string& s)
{
	size_t n = s.size();
	bool b = true;

	for (size_t i = 0; i < (n - 1); i++)
	{
		if (isDigit(s[i]) == false && (s[i] != '.') && (s[i] != ','))
			return false;
	}
	if (((s[n - 1] == '\n') || (s[n - 1] == '\r')) && (n > 1)) return b;
	else if (isDigit(s[n - 1]) == false) b = false;
	return b;
}

class Exc
{
private:
	std::string mess;
public:
	Exc(std::string m) :
			mess(m)
	{
	}
	void print(void)
	{
		cerr << mess << std::endl;
	}
};

double str2double(const string& s)
{
	if (isDouble(s) == false)
	{
		cerr << __FILE__ << ": str2double() input string (" << s
				<< ") is not a number " << "return 0" << endl;
		return 0;
	}

	double d;
	stringstream ss;
	ss << s;
	ss >> d;
	if ((ss.rdstate() == ios::failbit) || (ss.rdstate() == ios::badbit))
	{
		cerr << __FILE__ << ": str2double() io error occurred, " << "return 0"
				<< endl;
		return 0;
	}
	std::string t;
	ss >> std::skipws >> t;
	if (t != "")
	{
		cerr << __FILE__ << ": str2double() input string is not a number "
				<< "return 0" << endl;
		throw Exc("bad input");
		return 0;
	}

	return d;
}

int str2int(const string& s)
{
	if (isInteger(s) == false)
	{
		cerr << __FILE__ << ": str2int() input string (" << s
				<< ") is not a number " << "return 0" << endl;
		return 0;
	}
	int x;
	stringstream ss;
	ss << s;
	ss >> x;
	if ((ss.rdstate() == ios::failbit) || (ss.rdstate() == ios::badbit))
	{
		cerr << __FILE__ << ": str2int() io error occurred, return 0" << endl;
		return 0;
	}
	return x;
}

long str2long(const string& s)
{
	if (isInteger(s) == false)
	{
		cerr << __FILE__ << ": str2long() input string (" << s
				<< ") is not a number " << "return 0" << endl;
		return 0;
	}
	long x;
	stringstream ss;
	ss << s;
	ss >> x;
	if ((ss.rdstate() == ios::failbit) || (ss.rdstate() == ios::badbit))
	{
		cerr << __FILE__ << ": str2long() io error occurred, return 0" << endl;
		return 0;
	}
	return x;
}

bool startsWith(const string& s, const string& t)
{
	if (s.size() < t.size()) return false;
	size_t n = t.size();
	for (size_t i = 0; i < n; i++)
	{
		if (s[i] != t[i]) return false;
	}
	return true;
}

std::string double2str(const double d)
{
	stringstream ss;
	ss << d;
	if ((ss.rdstate() == ios::failbit) || (ss.rdstate() == ios::badbit))
	{
		cerr << __FILE__ << ": double2str() io error occurred, returning "
				<< "an empty string" << endl;
		return "";
	}
	return ss.str();
}

std::string int2str(const int x)
{
	stringstream ss;
	ss << x;
	if ((ss.rdstate() == ios::failbit) || (ss.rdstate() == ios::badbit))
	{
		cerr << __FILE__ << ": int2str() io error occurred, returning "
				<< "an empty string" << endl;
		return "";
	}
	return ss.str();
}

std::string long2str(const long x)
{
	stringstream ss;
	ss << x;
	if ((ss.rdstate() == ios::failbit) || (ss.rdstate() == ios::badbit))
	{
		cerr << __FILE__ << ": long2str() io error occurred, returning "
				<< "an empty string" << endl;
		return "";
	}
	return ss.str();
}

bool isDigit(const char c)
{
	if (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5'
			|| c == '6' || c == '7' || c == '8' || c == '9') return true;
	else return false;
}

bool isInteger(const std::string& s)
{
	size_t n = s.size();
	bool b = true;

	for (size_t i = 0; i < (n - 1); i++)
	{
		if (isDigit(s[i]) == false) return false;
	}
	if (((s[n - 1] == '\n') || (s[n - 1] == '\r')) && (n > 1)) return b;
	else if (isDigit(s[n - 1]) == false) b = false;
	return b;
}

//bool isDouble(const std::string& s)
//{
//    size_t n = s.size();
//    bool b = true;
//
//    for (size_t i = 0; i < (n - 1); i++)
//    {
//        if (isDigit(s[i]) == false && (s[i] != '.') && (s[i] != ','))
//            return false;
//    }
//    if (((s[n - 1] == '\n') || (s[n - 1] == '\r')) && (n > 1))
//        return b;
//    else if (isDigit(s[n - 1]) == false)
//        b = false;
//    return b;
//}
